/*
 ============================================================================
 Name		: MyDataCenter.cpp
 Author	  : 
 Version	 : 1.0
 Copyright   : copyright readever.cn
 2009-2010
 Description : CMyDataCenter implementation
 iHtmlControlֻ��һ�����ã�����������ʵ��������plugin����Щ
 ============================================================================
 */
#include "xml\feedbackhelper.h"
#include <ImageConversion.h> 

#include <html\htmlcontrol.h> 
#include <html\lirenderer.h>

#include <AKNAPPUI.h>
#include <bautils.h>
#include <EIKENV.H>
#include <EIKAPPUI.h>
#include <utf.h>

#include "CStreamAudioEngine.h"
#include "clientengine.h"
#include "downloadengine.h"

#include "mk4.h"
#include "mk4str.h"
#include "MyUtils.h"
#include "MyDataCenter.h"

#include "hm\htmldialog.h"

MyDataCenter::MyDataCenter()
	{
	// No implementation required
		iHtmlControl = NULL;
		iHistory = new (ELeave) CDesCArrayFlat(5);
	}

MyDataCenter::~MyDataCenter()
	{
	delete iMp3Stream;
	delete iDBStore;
	iDBInfo->Commit();
	delete iDBInfo;
	delete iDBBook;
	delete iDBTemp;
	
	delete iHistory;
	
 	delete iHttpEngine;
	delete iHttpDownload;
	}

MyDataCenter* MyDataCenter::NewLC()
	{
	MyDataCenter* self = new (ELeave) MyDataCenter();
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

MyDataCenter* MyDataCenter::NewL()
	{
	MyDataCenter* self = MyDataCenter::NewLC();
	CleanupStack::Pop(); // self;
	return self;
	}

void MyDataCenter::ConstructL()
	{

	}

void MyDataCenter::AddHistory(const TDesC& link)
{
//	CEikonEnv::Static()->InfoWinL(_L("his"), link);

	iHistory->AppendL(link);	
}

void MyDataCenter::AddBookToList(const TDesC& fullname, const TDesC& filename)
{
	char path[256];
	DBUtil::Static()->ConvertDesToStr(fullname, path);
	c4_Storage* tempbook  = new c4_Storage(path, false);
	c4_View view = tempbook->View("info");
	
	TBuf<256> buf;
	TPtrC8 bookname = DBUtil::Static()->FieldUtf8Value(&view, "bookname", 0);
	
	c4_View view2 = iDBInfo->View("booklist");
	c4_Row row;
	
	c4_BytesProp binfield("bookname");
	binfield(row) = binfield(view[0]);
	c4_StringProp sp("filename");
	char fname[100];
	DBUtil::Static()->ConvertDesToStr(filename, fname);
	sp(row) = fname;
	
	view2.Add(row);

	delete tempbook;
}

void MyDataCenter::ClientEvent(const int aClientID, const TDesC& aEventDescription)
{

}

void MyDataCenter::ClientReceived(const int aClientID, const TDesC8& aRevData)
{

}

void MyDataCenter::ClientBodyReceived(const int aClientID, const TDesC8& aBodyData)
{
	if(aClientID == iHttpEngine->iClientID)
		{
		CFeedbackHandler feedbackHandler;
		ParseXMLBuffer(aBodyData, &feedbackHandler);
		ParseRemoteFeedback(&feedbackHandler);
		}

}


bool MyDataCenter::GoBack()
{
	//step1, stop audio if need
	if(iMp3Stream)
		iMp3Stream->StopL();

	//step2
	int count = iHistory->Count();
	
	if(count == 0)
		return false;

	iHistory->Delete(count-1);
	count = iHistory->Count();
	if(count == 0)
		return false;			

	ProcessLink((*iHistory)[count-1], false);
	
	return true;
}

void MyDataCenter::HandleBufImageLoadEventL(CBufferedImageDecoder* aDecoder, const TDesC& aFileName)
{
	c4_View view = iDBStore->View("image");
	
	TBuf8<256> str8;
	int len = aFileName.Length();
	str8.Copy(aFileName.Right(len-4));//remove prefix of "mem."
	
	char* path = (char *)str8.Ptr();
	path[str8.Length()] = 0;
	
	int find = DBUtil::Static()->FindByStr(&view, "path", path);
	if(find < 0){ 
		//load in ebook
		if(iDBBook){
			c4_View vp = iDBBook->View("image");
			find = DBUtil::Static()->FindByStr(&vp, "name", path);
			if(find < 0) find = 0;
			else{
				TPtrC8 ptr = DBUtil::Static()->FieldUtf8Value(&vp, "data", find);
				aDecoder->OpenL(ptr);
				return;
			}
		}
		else
			find = 0;
	}
	
	//CEikonEnv::Static()->InfoWinL(_L("tewt"), aFileName);
	TPtrC8 ptr = DBUtil::Static()->FieldUtf8Value(&view, "data", find);
	aDecoder->OpenL(ptr);
}

void MyDataCenter::HandleHtmlCtlEventL(const THtmlCtlEvent& aEvent)
	{
		if(aEvent.iType == THtmlCtlEvent::EOnClick)
		{
			CHtmlElement* link = aEvent.iElement->ElementByTag(_L("a"));
			if(aEvent.iElement->TagName() == _L("a")) 
				link = aEvent.iElement;
			
			if(link == NULL) 
			return;
		
			TBuf<200> href;
			link->GetProperty(KHStrHref, href);
			ProcessLink(href);
		}
	}

void MyDataCenter::IssueHTTPPostL(const TDesC8& aUri,
						const TDesC8& aContentType,
						const TDesC8& aBody, MClientObserver* aObserver)
{
	MClientObserver* Observer = aObserver;
	if(Observer == NULL) Observer = this;
	iHttpEngine->IssueHTTPPostL(aUri, aContentType, aBody, Observer);
}

void MyDataCenter::Init(CHtmlControl* aHtmlControl, MPluginObserver* aObserver)
	{
	iObserver = aObserver;
	iHtmlControl = aHtmlControl;
	if(iHtmlControl == NULL)
		return;
	
	iHtmlControl->SetEventObserver(this);
	iDBBook = NULL;
	
	//database
	char drive = 'c';
#ifndef _DEBUG
	drive = 'e';
#endif

	TBuf8<256> path;

	//sound
	iMp3Stream = CStreamAudioEngine::NewL();
	//db
	char storepath[] = "c:\\data\\iRead\\iRead.bdb";
	storepath[0] = drive;
	iDBStore = new c4_Storage(storepath, true);		

	char infopath[] = "c:\\data\\iRead\\info.bdb";
	infopath[0] = drive;
	iDBInfo = new c4_Storage(infopath, true);		
	
	char temppath[] = "c:\\data\\itest\\temp.bdb";
	temppath[0] = drive;				
	iDBTemp = new c4_Storage(temppath, true);	
	
	//html styles
	iHtmlControl->ClearStyleSheet();	
	c4_View view = iDBStore->View("style");
	
	for(int i = 0; i < view.GetSize(); i++){
		TPtrC8 style = DBUtil::Static()->FieldUtf8Value(&view, "value", i);
		HBufC* styleData = CnvUtfConverter::ConvertToUnicodeFromUtf8L(style);
		iHtmlControl->AddStyleSheetL(*styleData);
		CleanupStack::PushL(styleData);
		CleanupStack::PopAndDestroy(styleData); // styleData
	}
	
	iHtmlControl->ClearContent();
	LoadMemPage(iDBStore, _L("template.htm"));
	LoadMemPage(iDBStore, _L("index.htm"), true);	
	//LoadMemPage(_L("test.htm"));
	iHtmlControl->RefreshAndDraw();
	
	iHmListView.iControl = iHtmlControl;
	
	//networking
 	iHttpEngine = CClientEngine::NewL(200, *this);
 	iHttpDownload = CDownloadEngine::NewL();
	}

void MyDataCenter::LoadBook(const TDesC& dbname)
{
	int find = dbname.Find(_L("http://"));
	if(find == 0)
		DownloadBook(dbname);
	else
		OpenBook(dbname);
}

void MyDataCenter::DownloadBook(const TDesC& dbname)
{
	iHttpEngine->CancelTransaction();
	iWaitDlg.Note(_L("download book"));
	TBuf8<256> path;
	path.Copy(dbname);
	iHttpDownload->GetRequestL(path);//_L8("http://www.haomail.net/download/test1.rdm"));
	//iHttpDownload->GetRequestL(_L8("http://www.haomail.net/down.txt"));
}

void MyDataCenter::OpenBook(const TDesC& dbname)
{		
	if(iDBBook) delete iDBBook;
	TBuf8<100> filename;
	#ifdef _DEBUG		
		filename.Copy(_L8("c:\\data\\iRead\\"));
	#else
		filename.Copy(_L8("e:\\data\\iRead\\"));		
	#endif
		
	filename.Append(dbname);
	iCurrentDBFile.Copy(filename);

	TBool exist = BaflUtils::FileExists(CEikonEnv::Static()->FsSession(), iCurrentDBFile);
	if(exist == EFalse){
		CEikonEnv::Static()->InfoWinL(_L("Warnning"), _L("not found db file"));
		return;
	}
	
	char* filepath = (char *)filename.Ptr();
	filepath[filename.Length()] = '\0';//very important
	//	if(exist pah)
	iDBBook = new c4_Storage(filepath, false);		
	//get homeurl
	c4_View view = iDBBook->View("info");
	TPtrC8 homeurl8 = DBUtil::Static()->FieldStr8Value(&view, "homeurl", 0);
	TBuf<50> temp; temp.Copy(homeurl8);
	TBuf<100> homeurl; homeurl.Copy(_L("book://"));
	homeurl.Append(temp);
	LoadMemPage(iDBBook, homeurl, true);//_L("book://index.htm"), true);
}

/*
 * 主要完成2件事情
 * 1. 根据path名称判断是否执行某个函数
 * 2. 根据页面模块分析。。。。
 */
void MyDataCenter::ParsePage(const TDesC& path)
	{
	//分析页面URL参数
	TPtrC pagefunc = DBUtil::Static()->GetPageFunc(path);
	if(pagefunc == _L("updatebooklist"))
		{
			Post(pagefunc);	
		}
	else if(pagefunc == _L("getbookdesc"))
		{
			PF_BookDesc(path);
		}
	else if(pagefunc != _L(""))
		CEikonEnv::Static()->InfoWinL(_L("no pagefunction"), pagefunc);
	
	//分析当前页面内容模板
	CHtmlElement* item = iHtmlControl->Element(_L("dynlist"));
	if(item){
		int bufsize;
		item->GetProperty(KHStrBufSize, bufsize);
		if(bufsize > 50)
			return;
		iHmListView.ParsePage(iHtmlControl);
		return;
	}
	
	//是否有数据库模板?
	item = iHtmlControl->Element(_L("dbdata"));
	if(item){
		int bufsize;
		item->GetProperty(KHStrBufSize, bufsize);
		if(bufsize > 50)
			return;
		iHmDataBase.ParseData(iHtmlControl);
		return;
	}	
	
	}

void MyDataCenter::ParseRemoteFeedback(const CFeedbackHandler* feedback)
{
	iWaitDlg.EndWait();
	if(!feedback->iDataBuffer[data_func]){
		return;
	}
	
	if(*(feedback->iDataBuffer[data_func]) == _L("ebk_updatebooklist"))
	{
		//reload
		LoadMemPage(iDBStore, _L("booklist.htm"), false);
	}
	else if(*(feedback->iDataBuffer[data_func]) == _L("ebk_getbookdesc"))
	{
		//CEikonEnv::Static()->InfoWinL(_L("test"), _L("ttt"));
		//reload
		int count = iHistory->Count();
		LoadMemPage(iDBStore, (*iHistory)[count-1], false);
	}

	
}

void MyDataCenter::ParseXMLBuffer(const TDesC8& aBuffer, MSyDocHandler* aDocHandler)
{
	// 2. Create the XML Parser	and set the default document handlers
	CSyParser*   reader = CSyParser::NewLC(TPtrC());		

//	RTest test(_L("XML String"));
//	CFeedbackHandler feedbackHandler(test);
	reader->SetHandler(aDocHandler);

	// 3. We set up the buffer with a default size of 128 bytes.
	//    This buffer is set purposly small so that we execute the
	//    parse stuff as often as possible to show aynchronous parsing
	//    We alse set up some loop variables
	const int KMaxBufLen = 128;
	TBuf8<KMaxBufLen> buf;
	TBool isFinal = ETrue;
	TSyExpatStatus status = EStatusOk;
		
	int LenToRead = aBuffer.Length();
	long cursor = 0;
	Byte* bufptr = (Byte*)aBuffer.Ptr();	
	do
	{
		// 4. First read some data
		//    Note that if there was an error reading there
		//    data an error will be returned, this is not the
		//    case with eof where the buffer will be smaller than
		//    maxBufLen.
		int len = KMaxBufLen;
		if(LenToRead < KMaxBufLen)
			len = LenToRead;
			
		buf.Copy(bufptr, len);
		bufptr += KMaxBufLen;
		LenToRead -= KMaxBufLen;

		// 5. Next we attempt to parse the result buffer
		//    or if we reached the end of the file the 
		//    partial buffer
		isFinal = (LenToRead <= 0);
					
		status = reader->Parse(buf, isFinal);
		// 6. When the parser returns an error
		//    we log it 
		//    Otherwise if there is no more data
		//    then we report we have finished
		if (status != EStatusOk)
		{
			_LIT(KError,"Error on Line %d Column %d\n");
			CEikonEnv::Static()->InfoMsg(KError);
			///test.Printf(KError, reader->GetCurrentLineNumber(), reader->GetCurrentColumnNumber());
		}
		else
		{
			if (isFinal)
			{
				_LIT(KFinished, "Finished parsing file\n");
//				CEikonEnv::Static()->InfoMsg(KFinished);
				///test.Printf(KFinished);
			}
		}
		
		// 7. finally we see if we have to loop round
		//    any more - we stop if we find an error or
		//    we have reached the end of the file
	} while (status == EStatusOk && !isFinal);		

	// 8.  Finally delete the parser
	CleanupStack::PopAndDestroy(1);
}

void MyDataCenter::PF_BookDesc(const TDesC& path)
{
	int bookid = DBUtil::Static()->GetPageIntPara(path, 0);
	c4_View view = iDBInfo->View("remotebooklist");	
	int find = DBUtil::Static()->FindByInt(&view, "bookid", bookid);
	if(find < 0) return;

	int done = DBUtil::Static()->FieldIntValue(&view, "done", find);
	if(done == 0){
		Post(_L("ebk_getbookdesc"));
		//CEikonEnv::Static()->InfoWinL(_L("test"), _L("need download detail infor..."));
		iWaitDlg.Note(_L("Get more information. Pls wait..."), 5);
		return;
	}
		

	CHtmlElement* divbookname = iHtmlControl->Element(_L("bookname"));
	TPtrC bookname = DBUtil::Static()->FieldUnicodeValue(&view, "bookname", find);
	divbookname->SetProperty(KHStrInnerText, bookname);
	

	CHtmlElement* divbookbrief = iHtmlControl->Element(_L("brief"));
	TPtrC brief = DBUtil::Static()->FieldUnicodeValue(&view, "brief", find);
	divbookbrief->SetProperty(KHStrInnerText, brief);

	CHtmlElement* alinkdown = iHtmlControl->Element(_L("down"));
	TPtrC8 down8 = DBUtil::Static()->FieldStr8Value(&view, "bookurl", find);
	TBuf<200> downurl;
	downurl.Copy(down8);
	alinkdown->SetProperty(KHStrHref, downurl);
	
	iHtmlControl->RefreshAndDraw();
}

extern int gBinfilepos;
void MyDataCenter::PlayMp3(const TDesC& media)
{
	//iMp3Stream->OpenL(_L("c:\\data\\test.mp3"));
	//return;
	TPtrC audiofile = DBUtil::Static()->GetRealPath(media);

	c4_View view = iDBBook->View("audio");
	char audio[256];
	DBUtil::Static()->ConvertDesToStr(audiofile, audio);
	
	int find = DBUtil::Static()->FindByStr(&view, "name", audio);
	if(find < 0) return;
	
	c4_BytesProp binfield("data");
	c4_Bytes bin = binfield(view[find]);
		
	int mediaoffset = gBinfilepos;
	int mediarealsize = bin.Size();

	//TBuf<100> test;
	//test.Format(_L("%d,%d"), mediaoffset, mediarealsize);
	//CEikonEnv::Static()->InfoWinL(_L("Warnning"), test);
	
	iMp3Stream->OpenL(iCurrentDBFile, mediaoffset, mediarealsize);
}

/*
 * 如果需要知道一些参数，可以通过pagepath获取
 */
void MyDataCenter::Post(const TDesC& poststr)
{
	if(poststr == _L("updatebooklist"))
	{
		{
			c4_View view = iDBTemp->View("booklist");
			view.RemoveAll();
		}
		c4_View view = iDBInfo->View("remotebooklist");
		int size = view.GetSize();
		int lastid = 0;
		if(size > 0)
			lastid = DBUtil::Static()->FieldIntValue(&view, "bookid", size-1);

		_LIT8(postdata,  
			"<xml version='1.0'>"
			"<data>"
			"<func>ebk_updatebooklist</func>"
			"<lastbid>%d</lastbid>"
			"</data>");
	
		HBufC8* iBuf8 = HBufC8::NewLC(500);	
		TPtr8 ptr8 = iBuf8->Des();
		ptr8.Format(postdata, lastid);
	
		//_LIT8(KRemoteIP, "http://221.130.184.102:8081/");
		_LIT8(KRemoteIP, "http://127.0.0.1:8081/");	
		IssueHTTPPostL(KRemoteIP, _L8("*.*"), ptr8, this);
		CleanupStack::PopAndDestroy(iBuf8);
		iWaitDlg.Note(_L("updating booklist..."));
	}
	else if(poststr == _L("ebk_getbookdesc"))
	{
		int count = iHistory->Count();
		int bookid = DBUtil::Static()->GetPageIntPara((*iHistory)[count-1], 0);

		_LIT8(postdata,  
			"<xml version='1.0'>"
			"<data>"
			"<func>ebk_getbookdesc</func>"
			"<bookid>%d</bookid>"
			"</data>");
	
		HBufC8* iBuf8 = HBufC8::NewLC(500);	
		TPtr8 ptr8 = iBuf8->Des();
		ptr8.Format(postdata, bookid);
	
		//_LIT8(KRemoteIP, "http://221.130.184.102:8081/");
		_LIT8(KRemoteIP, "http://127.0.0.1:8081/");	
		IssueHTTPPostL(KRemoteIP, _L8("*.*"), ptr8, this);
		CleanupStack::PopAndDestroy(iBuf8);
	}
}

bool MyDataCenter::ProcessLink(const TDesC& paras, bool addhistory)
{
	TBuf<256> path;
	path.Copy(paras);
	//CEikonEnv::Static()->InfoWinL(_L("link"), path);
	if(paras == KNullDesC){
		CEikonEnv::Static()->InfoWinL(_L("info"), _L("empty link"));
		return false;
	}
		

	//convert into unix path
	for(int i = 0; i < path.Length(); i++){
		if(path[i] == '\\') path[i] = '/';
	}

	if(paras.Find(_L(".rdm")) >= 0)
	{
		LoadBook(paras);
		return false;
	}

	if(paras.Find(_L(".mp3")) >= 0)
	{
		PlayMp3(paras);
		return false;
	}
	
	c4_Storage* store = iDBStore;
	if(DBUtil::Static()->FindBookPrefix(path))
			store = iDBBook;
		
	LoadMemPage(store, path, addhistory);
}

void MyDataCenter::LoadMemPage(c4_Storage* store, const TDesC& path, bool addhistory)
	{
		if(store == NULL){
			CEikonEnv::Static()->InfoWinL(_L("error"), _L("Open empty database"));
			return;
		}
		
		if(path.Find(_L("self?")) == 0)
			{
			//ProcessPageParameters(path);
			return;
			}


		TPtrC pagename = DBUtil::Static()->GetRealPath(path);

		if(addhistory)
			AddHistory(path);	


		if(pagename == _L(""))
			return;
		
		//c4_View view = iDBStore->View("page");
		c4_View view = store->View("page");

		char szpagename[256];
		DBUtil::Static()->ConvertDesToStr(pagename, szpagename);
				
		int find = DBUtil::Static()->FindByStr(&view, "name", szpagename);
		
		if(find == -1){ 
			find = 0;
			CHtmlElement* pageContainer = iHtmlControl->Element(_L("iContent"));
			if(pageContainer){
				TBuf<200> errmsg;
				errmsg.Format(_L("Not found %S"), &path);
				pageContainer->SetProperty(KHStrInnerHtml, errmsg);
				iHtmlControl->RefreshAndDraw();
			}
			return;
		}
		
		TPtrC8 content8 = DBUtil::Static()->FieldUtf8Value(&view, "content", find);
		HBufC* pageData = CnvUtfConverter::ConvertToUnicodeFromUtf8L(content8);
		CleanupStack::PushL(pageData);

		CHtmlElement* pageContainer = iHtmlControl->Element(_L("iContent"));
		if(pageContainer){
			pageContainer->SetProperty(KHStrInnerHtml, KNullDesC);
		}

		if(pageContainer)
			pageContainer->SetProperty(KHStrInnerHtml, *pageData);
		else
			iHtmlControl->AppendContentL(*pageData);
			
		iHtmlControl->RefreshAndDraw();

			CleanupStack::PopAndDestroy(pageData); // pageData		

		//finally
		//default
		ParsePage(path);
		//看看这页有没有音频需要处理 
		PageMedia(&view, find);
	}

void MyDataCenter::PageMedia(c4_View* view, int rowid)
{
	TPtrC8 audio8 = DBUtil::Static()->FieldStr8Value(view, "bkaudio", rowid);
	TBuf<50> audio; audio.Copy(audio8);
	
	if(audio != _L(""))
		PlayMp3(audio);
//	CEikonEnv::Static()->InfoWinL(_L("auido"), audio);
	
}

void MyDataCenter::TestMe()
	{
	}

void MyDataCenter::RenderListItemL(CHtmlElement* aElement, TInt aIndex)
{

}

TKeyResponse MyDataCenter::SuperHandleKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType )
{
	if( aType == EEventKeyDown )
		{ 
		TBuf<40> scanCode; 
		scanCode.AppendNum(aKeyEvent.iScanCode); 
			
		if(aKeyEvent.iScanCode == 165)//right softkeyback
			{
			//CancelLoading();

			//if(IsMenuVisible())
			//	HideMenu();
			
			if(GoBack() == false)
				{
					if(iObserver)
					{
						CEikonEnv::Static()->InfoMsg(scanCode);
						iObserver->UnloadPlugin(NULL);
						return EKeyWasConsumed;
					}
					else{
						CAknAppUiBase* appui = (CAknAppUiBase*)CEikonEnv::Static()->EikAppUi();
						appui->Exit();
						return EKeyWasConsumed;
					}
				}
			else
				return EKeyWasConsumed;
				

			}
		}
	
	return EKeyWasNotConsumed;
}
